import { setPx, validatenull, addParam, loadFont } from "./util";
import { markRaw } from "vue";
import config from "./config";
import commonOption from "./option";
import crypto from "@/datav/utils/crypto";
import { getFunction, funEval, uuid } from "@/datav/utils/utils";
import COMMON from "@/datav/config";
export default (() => {
	return {
		props: {
			stylesFormatter: Function,
			dataFormatter: Function,
			titleFormatter: Function,
			labelFormatter: Function,
			clickFormatter: Function,
			sqlFormatter: Function,
			recordFormatter: Function,
			formatter: Function,
			echartFormatter: Function,
			dataQueryType: String,
			dataQuery: String,
			dataHeader: String,
			fontFamily: String,
			width: {
				type: [Number, String],
				default: 600,
			},
			height: {
				type: [Number, String],
				default: 600,
			},
			theme: {
				type: String,
			},
			child: {
				type: Object,
				default: () => {
					return {};
				},
			},
			record: {
				type: String,
			},
			public: {
				type: String,
			},
			sql: {
				type: String,
			},
			time: {
				type: Number,
				default: 0,
			},
			proxy: {
				type: Boolean,
			},
			url: {
				type: String,
			},
			wsUrl: {
				type: String,
			},
			disabled: {
				type: Boolean,
				default: true,
			},
			dataType: {
				type: Number,
				default: 0,
			},
			dataMethod: {
				type: String,
				default: "get",
			},
			id: {
				type: String,
				default: "main_" + uuid(),
			},
			data: {
				type: [Object, String, Array],
			},
			component: {
				type: Object,
				default: () => {
					return {};
				},
			},
			option: {
				type: Object,
				default: () => {
					return {};
				},
			},
		},
		mixins: [commonOption],
		data() {
			return {
				headerHeight: "",
				checkChart: "",
				myChart: "",
				dataChart: [],
				dataAxios: {},
				dataParams: {},
				wsClient: {},
				styles: {},
				appendCheck: {},
				appendObj: {},
				appendList: [],
				className: "",
			};
		},
		watch: {
			data() {
				this.updateData();
			},
			dataAppend(val) {
				this.appendObj = {};
				this.appendList = [];
				if (!val) {
					this.appendCheck = clearInterval(this.appendCheck);
				} else {
					this.dataChart = [];
				}
				this.updateData();
			},
			echartFormatter() {
				this.updateChart();
			},
			width() {
				this.$nextTick(() => {
					this.updateChart();
				});
			},
			height() {
				this.$nextTick(() => {
					this.updateChart();
				});
				this.updateChart();
			},
			theme() {
				this.myChart.dispose();
				this.init();
			},
			option: {
				handler() {
					this.updateChart();
				},
				deep: true,
			},
		},
		computed: {
			count() {
				return this.option.count;
			},
			dataAppend() {
				return this.option.dataAppend;
			},
			dataChartLen() {
				return (this.dataChart || []).length;
			},
			switchTheme() {
				return this.validData(this.option.switchTheme, false);
			},
			name() {
				let className = this.$el.className.split(" ")[0];
				const result = className.replace(config.name, "");
				return result;
			},
			minWidth() {
				const val = this.option.minWidth;
				if (val > this.width) return val;
			},
			styleChartName() {
				const obj = {
					fontFamily: loadFont(this.component.fontFamily),
					width: setPx(this.minWidth || this.width),
					height: setPx(this.height),
					opacity: this.component.opacity || 1,
					transform: `scale(${
						this.component.scale || 1
					}) perspective(${
						this.component.perspective || 500
					}px) rotateX(${this.component.rotateX || 0}deg) rotateY(${
						this.component.rotateY || 0
					}deg) rotateZ(${this.component.rotateZ || 0}deg)`,
				};
				return obj;
			},
			styleSizeName() {
				return Object.assign(
					{
						width: setPx(this.width),
						height: setPx(this.height),
					},
					(() => {
						if (this.minWidth) {
							return {
								overflowX: "auto",
								overflowY: "hidden",
							};
						}
						return {};
					})(),
					this.styles
				);
			},
		},
		mounted() {
			this.init();
		},
		methods: {
			init() {
				this.className = `animated ${this.component.animated || ""}`;
				const main = this.$refs[this.id];
				if (main) {
					// 判断是否图表去初始化
					const isChart = config.echart.includes(this.name);
					if (isChart)
						this.myChart = markRaw(
							window.echarts.init(main, this.theme)
						);
				}
				this.updateChart();
				this.updateData();
			},
			getItemRefs() {
				let refList = this.$parent.$parent.$refs;
				let result = {};
				Object.keys(refList).forEach((ele) => {
					if (ele.indexOf(COMMON.NAME) !== -1) {
						result[ele.replace(COMMON.NAME, "")] = refList[ele][0];
					}
				});
				return result;
			},
			updateChart() {},
			updateClick(params) {
				let refList = this.getItemRefs();
				let indexList = this.child.index;
				let paramName = this.child.paramName;
				let paramValue = this.child.paramValue || "value";
				let paramList = this.child.paramList || [];
				let p = {};
				if (!validatenull(paramName) && !validatenull(paramValue)) {
					p[paramName] = params[paramValue];
				}
				if (!validatenull(paramList)) {
					paramList.forEach((ele) => {
						p[ele.name] = params[ele.value];
					});
				}
				if (!validatenull(p)) {
					Object.keys(refList).forEach((ele) => {
						if (indexList.includes(ele)) refList[ele].updateData(p);
					});
				}
			},
			updateAppend(result) {
				if (this.validatenull(this.appendObj)) {
					this.appendList = result;
					this.appendObj = result[0];
				} else {
					let appendList = [];
					for (let i = 0; i < result.length; i++) {
						const ele = result[i];
						if (ele.id === this.appendObj.id) break;
						else appendList.push(ele);
					}
					this.appendObj = result[0];
					appendList.reverse().forEach((ele) => {
						this.appendList.unshift(ele);
					});
				}
				if (this.validatenull(this.appendCheck)) {
					this.appendCheck = setInterval(() => {
						let length = this.appendList.length - 1;
						if (length >= 0) {
							let obj = this.appendList.splice(length, 1)[0];
							this.dataChart.unshift(obj);
							let len = this.dataChart.length;
							if (len > this.count) {
								this.appendList.splice(len - 1, 1);
							}
						}
					}, 2000);
				}
			},
			// 更新数据核心方法
			updateData(p = {}) {
				let record,
					key = false;
				let isRecord = this.dataType === 4;
				this.dataParams = Object.assign(this.dataParams, p);
				return new Promise((resolve, reject) => {
					this.resetData && this.resetData();
					if (key) return;
					key = true;
					let safe = this;
					const formatter = (data, params) => {
						// if (isRecord) {
						// 	const dataFormatter = getFunction(
						// 		safe.dataFormatter
						// 	);
						// 	if (typeof dataFormatter == "function") {
						// 		data = dataFormatter(data);
						// 	}
						// }
						if (typeof this.dataFormatter === "function") {
							data = this.dataFormatter(
								data,
								params,
								this.getItemRefs()
							);
						}
						return data;
					};
					const getData = () => {
						safe = record || this;
						key = false;
						let isApi = safe.dataType === 1;
						let isSql = safe.dataType === 2;
						let isWs = safe.dataType === 3;
						this.closeClient();
						const bindEvent = () => {
							this.updateChart();
							if (this.myChart) this.bindClick();
							if (typeof this.stylesFormatter === "function") {
								this.styles =
									this.stylesFormatter(
										this.dataChart,
										this.dataParams,
										this.getItemRefs()
									) || {};
							}
							resolve(this.dataChart);
						};
						if (isApi) {
							let url = safe.url;
							if (this.validatenull(url)) return;
							let dataQuery = getFunction(safe.dataQuery);
							dataQuery =
								(typeof dataQuery === "function" &&
									dataQuery(url)) ||
								{};
							let dataHeader = getFunction(safe.dataHeader);
							dataHeader =
								(typeof dataHeader === "function" &&
									dataHeader(url)) ||
								{};
							let params = Object.assign(
								dataQuery,
								this.dataParams
							);
							let axiosParams = {};
							if (["post", "put"].includes(safe.dataMethod)) {
								axiosParams.data = params;
								if (safe.dataQueryType == "form") {
									let formData = new FormData();
									Object.keys(params).forEach((ele) => {
										formData.append(ele, params[ele]);
									});
									axiosParams.data = formData;
								}
							} else if (
								["get", "delete"].includes(safe.dataMethod)
							) {
								axiosParams.params = params;
							}
							this.$axios({
								...{
									method: safe.dataMethod,
									url: url,
									headers: dataHeader,
								},
								...axiosParams,
							}).then((res) => {
								this.dataAxios = res;
								let result = res;
								result = formatter(result, params);
								if (this.dataAppend) {
									this.updateAppend(result);
								} else {
									this.dataChart = result;
								}
								bindEvent();
							});
						} else if (isWs) {
							let url = safe.wsUrl;
							if (this.validatenull(url)) return;
							let dataQuery = getFunction(safe.dataQuery);
							dataQuery =
								(typeof dataQuery === "function" &&
									dataQuery(url)) ||
								{};
							let params = Object.assign(
								dataQuery,
								this.dataParams
							);
							url = url + addParam(params);
							this.wsClient = new WebSocket(url);
							this.wsClient.onmessage = (msgEvent = {}) => {
								let result = JSON.parse(msgEvent.data);
								this.dataChart = formatter(
									result,
									this.dataParams
								);
								bindEvent();
							};
						} else if (isSql) {
							let sql = JSON.parse(crypto.decrypt(safe.sql));
							let result;
							this.sqlFormatter({
								dataSourceId: sql.id,
								sql: sql.sql,
							}).then((res) => {
								result = res.json;
								this.dataChart = formatter(
									result,
									this.dataParams
								);
								bindEvent();
							});
						} else if (isRecord) {
							this.recordFormatter(this.record).then((res) => {
								const data = res;
								this.dataChart = data;
								bindEvent();
							});
							// bindEvent();
						} else {
							let result = safe.data;
							this.dataChart = formatter(result, this.dataParams);
							bindEvent();
						}
					};
					const sendData = () => {
						this.$nextTick(() => {
							getData();
							clearInterval(this.checkChart);
							if (this.time !== 0 && this.disabled) {
								this.checkChart = setInterval(() => {
									getData();
								}, this.time);
							}
						});
					};
					sendData();
				});
			},
			// 绑定点击事件
			bindClick() {
				this.myChart.off("click");
				this.myChart.on("click", (e) => {
					this.updateClick(this.dataChart[e.dataIndex] || e);
					this.clickFormatter &&
						this.clickFormatter(
							Object.assign(e, {
								data: this.dataChart,
							}),
							this.getItemRefs()
						);
				});
			},
			// 下面俩都是chart的公共的方法,就放这里面共用
			getColor(index, first) {
				const barColor = this.option.barColor || [];
				if (barColor[index]) {
					const color1 = barColor[index].color1;
					const color2 = barColor[index].color2;
					const postion = (barColor[index].postion || 0.9) * 0.01;
					if (first) return color1;
					if (color2) {
						return {
							type: "linear",
							x: 0,
							y: 0,
							x2: 0,
							y2: 1,
							colorStops: [
								{
									offset: 0,
									color: color1, // 0% 处的颜色
								},
								{
									offset: postion,
									color: color2, // 100% 处的颜色
								},
							],
							global: false, // 缺省为 false
						};
					}
					return color1;
				}
			},
			getHasProp(isHas, propObj, staticObj = {}) {
				return Object.assign(
					(() => {
						return isHas ? propObj : {};
					})(),
					staticObj
				);
			},
			closeClient() {
				this.wsClient.close && this.wsClient.close();
			},
		},
		beforeDestroy() {
			clearInterval(this.checkChart);
			this.closeClient();
		},
	};
})();
